<?php
declare (strict_types = 1);

namespace app\common\model\system;

use app\admin\traits\GetTableData;
use think\facade\Cache;
use think\Model;

/**
 * @mixin think\Model
 */
class Menu extends Model
{
    use GetTableData;

    //菜单类型
    const TYPE_INDEX = 1;
    const TYPE_ADMIN = 2;

    const CACHE_INDEX_MENU = 'cache_index_menu';
    const CACHE_ADMIN_MENU = 'cache_admin_menu';

    // 设置字段信息
    protected $schema = [
        'id'            => 'int',
        'name'          => 'string',
        'route'         => 'string',
        'icon'          => 'string',
        'sort'          => 'int',
        'parent_id'     => 'int',
        'type'          => 'int',
        'create_time'   => 'int',
        'update_time'   => 'int',
    ];

    // 类型转换
    protected $type = [
        'id'            => 'integer',
        'sort'          => 'integer',
        'parent_id'     => 'integer',
        'type'          => 'integer',
    ];


    //获取顶级菜单下拉列表数据
    public static function getParents(){
        return static::where('parent_id','=',0)
            ->order(['id'=>'ASC'])
            ->column('name','id');
    }

    //关联数据
    public function submenus()
    {
        return $this->hasMany(static::class, 'parent_id','id');
    }

    //删除之后
    public static function onAfterDelete(Model $model)
    {
        if ($model->parent_id === 0){
            static::destroy(function($query) use ($model){
                $query->where('parent_id','=',$model->id);
            });
        }
    }


    //获取分类列表table数据
    public static function getListData(array $ruleWhere = []){
        //要查询的字段
        $fields = [
            'fields' =>['id','name', 'route', 'icon', 'sort','parent_id','type','create_time','update_time'],
            'with' => ['submenus'],
            'withCount' => [],
        ];

        //(构建查询条件)
        $where[] = ['parent_id','=',0];
        if ($type = input('type/s')){
            $where[] = ['type','=',$type];
        }
        if ($name = input('name/s')){
            $where[] = ['name','=',$name];
        }


        //排序
        $order = ['id'=>'desc','create_time'=>'desc'];

        //[count:查询到的数目, list:记录列表]
        $data = static::operateDatum($where, $fields, $order,$ruleWhere);


        return [
            'count' => $data['count'],
            'data' => static::tree($data['list'])
        ];
    }

    //格式化菜单数据获取数据树
    private static function tree(array $data){
        if (empty($data)) return [];

        $ret = [];
        foreach ($data as $k => $v){
            if ($v['parent_id'] === 0){
                $submenus = $v['submenus'];

                $v['submenus'] = count($submenus) > 0 ? true : false;
                $ret[] = $v;

                if (empty($submenus)) continue;
                foreach($submenus as $kk => $vv){
                    if ($vv['parent_id'] == $v['id']){
                        $vv['name'] = '/--' . $vv['name'];
                        $ret[] = $vv;
                    }
                }
            }
        }

        return $ret;
    }


    /**
     * 获取前端导航数据
     */
    public static function getMainNavs(){
        if(!$frontMenus = Cache::get(static::CACHE_INDEX_MENU)){
            $frontMenus = static::where([
                ['type', '=', static::TYPE_INDEX],
                ['parent_id', '=', 0]
            ])
                ->field(['id','name','route','icon','sort'])
                ->with(['submenus'])
                ->order(['sort'=>'ASC'])
                ->select()
                ->toArray();
            Cache::set(static::CACHE_INDEX_MENU, $frontMenus, 12 * 3600);
        }

        return static::toFormat($frontMenus);
    }

    /**
     * 格式化前端菜单
     */
    private static function toFormat(array $menus){
        if (empty($menus)) return [];
        foreach ($menus as &$menu){
            $menu['url'] = $menu['route'] ? (string)url($menu['route']) : 'javascript:;';
            $menu['active'] = strtolower(request()->completePathInfo()) === strtolower($menu['route']);

            //遍历子菜单
            if(!empty($menu['submenus'])){
                foreach ($menu['submenus'] as $kk => &$vv){
                    $vv['url'] = $vv['route'] ? (string)url($vv['route']) : 'javascript:;';
                    $vv['active'] = strtolower(request()->completePathInfo()) === strtolower($vv['route']);
                }
            }
        }
        return $menus;
    }

    /**
     * 获取后台菜单数据
     */
    public static function getAdminNavs(){
        if (!$adminMenus = Cache::get(static::CACHE_ADMIN_MENU)){
            $adminMenus = static::where([
                ['type', '=', static::TYPE_ADMIN],
                ['parent_id', '=', 0]
            ])
                ->field(['id','name','icon','route','sort'])
                ->with(['submenus'])
                ->order(['sort'=>'ASC'])
                ->select()
                ->toArray();
            //缓存
            Cache::set(static::CACHE_ADMIN_MENU, $adminMenus, 12 * 3600);
        }

        return static::toAdminFormat($adminMenus);
    }

    /**
     * 格式化后台菜单
     */
    private static function toAdminFormat(array $menus){
        if (empty($menus)) return [];
        $ret = [];
        foreach ($menus as $k => $menu){
            //检索权限
            if (empty($menu['submenus']) && !empty($menu['route'])){
                if( ! static::allow($menu['route']) ) continue;
            }

            $tmp['title'] = $menu['name'];
            $tmp['href']  = empty($menu['submenus']) ? (string)url($menu['route']) : '';
            $tmp['icon']  = htmlspecialchars_decode($menu['icon']);

            if ($k === 0){
                $tmp['spread']   = $k === 0;
                $tmp['isCheck']  = $k === 0;
            }



            //遍历子菜单
            if(!empty($menu['submenus'])){
                foreach ($menu['submenus'] as $kk => $vv){

                    //检索权限
                    if (!empty($vv['route'])){
                        if( !static::allow($vv['route']) ) continue;
                    }


                    $tmp2['title'] = $vv['name'];
                    $tmp2['href'] = (string)url($vv['route']);
                    $tmp2['icon'] = htmlspecialchars_decode($vv['icon']);

                    $tmp['children'][] = $tmp2;
                    unset($tmp2);
                }
            }

            //删除空顶级菜单
            if (!empty($tmp['href']) || !empty($tmp['children'])){
                $ret[] = $tmp;
            }
            unset($tmp);
        }

        return $ret;
    }


    /**
     * #判断是否允许当前用户访问当前路由
     * @param string $pathInfo
     * @return bool #允许的话返回权限规则，否则返回false
     */
    private static function allow(string $pathInfo){
        if (empty($pathInfo) || strpos($pathInfo, '/') === false) return false;

        //分组权限
        $pathArr = explode('/', $pathInfo);
        $group = parse_name($pathArr[0] . '/*');

        $permissions = array_keys(request()->related['permission']);

        //如 category/index 或 category/* 都可以访问category/index路由
        $res =  in_array($pathInfo, $permissions) ||
            in_array($group, $permissions) ||
            in_array('*/*', $permissions);

        //允许访问
        return $res;
    }


}
